//
//  TBProcessChainMC.m
//  TBShare
//
//  Created by JIENING ZHANG on 2020/2/25.
//  Copyright © 2020 taobao. All rights reserved.
//

#import "TBProcessChainMC.h"
#import "TBProcessNodeMC.h"

#ifdef DEBUG
#import <AssetsLibrary/AssetsLibrary.h>
#import <Photos/Photos.h>
#endif

@interface TBProcessChainMC ()

@property (nonatomic, strong) NSDate  *endWorkTs;
@property (nonatomic, strong) NSDate  *beginWorkTs;

@property (nonatomic, strong) NSMutableArray<TBProcessNodeMC *> *processNodeArray;

// 关键节点列表，这些节点报错，将结束整个处理流程
@property (nonatomic, strong) NSMutableArray<TBProcessNodeMC *> *keyProcessNodes;

@property (nonatomic, strong) TBProcessNodeMC *finishProcessNode;

@property (nonatomic, strong) NSOperationQueue *handleQueue;

@property (nonatomic, strong) NSMutableArray<NSDictionary *> *logArray;
@property (nonatomic, strong) NSOperationQueue *logQueue;

@property (nonatomic) CGSize chainImageSize;
@property (nonatomic) BOOL applyLog;
@end


@implementation TBProcessChainMC

- (instancetype)init {
    if (self = [super init]) {
        _processNodeArray = [NSMutableArray array];
        _keyProcessNodes = [NSMutableArray array];
        _logArray = [NSMutableArray array];
        
        _chainImageSize = CGSizeZero;
        
        _processSharedInfo = [NSMutableDictionary dictionary];
        
        _handleQueue = [[NSOperationQueue alloc] init];
        _handleQueue.maxConcurrentOperationCount = 1;
        
        _logQueue = [[NSOperationQueue alloc] init];
        _logQueue.maxConcurrentOperationCount = 1;
    }
    return self;
}

- (void)dealloc {
    [_processNodeArray removeAllObjects];
    _processNodeArray = nil;
    
    [_keyProcessNodes removeAllObjects];
    _keyProcessNodes = nil;
    
    [_processSharedInfo removeAllObjects];
    _processSharedInfo = nil;
    
    [_logArray removeAllObjects];
    _logArray = nil;
    
    [_handleQueue cancelAllOperations];
    _handleQueue = nil;
}

#pragma mark - 调测辅助
-(void) setLogable:(BOOL)logable {
    _applyLog = logable;
}
- (void) logNodeEvent:(id)info {
    [self logEvent:info pre:@"(--)"];
}
- (void) logEvent:(id)info {
    [self logEvent:info pre:@"--->"];
}

- (void) logEvent:(id)info pre:(NSString *)pre{
    if(! _applyLog) {
        return;
    }
    if(!info) {
        return;
    }
    NSDate *ts = [NSDate new];
    
    NSString *eventStr = @"";
    if([info isKindOfClass:[NSDictionary class]]) {
        
    //} else if([info isKindOfClass:[NSDictionary class]]) {
        eventStr = @"{";
        NSDictionary *infoDic = (NSDictionary *)info;
        for(NSString *key in infoDic) {
            eventStr = [NSString stringWithFormat:@"%@ %@:%@,", eventStr, key, infoDic[key]];
        }
        eventStr = [eventStr stringByAppendingString:@"}"];
    } else {
        eventStr = [info description];
    }
    
    NSString *logStr = [NSString stringWithFormat:@"%@ %.3f ms, %@, thread:%@", pre, 1000.f*(ts.timeIntervalSince1970 - self.beginWorkTs.timeIntervalSince1970), eventStr, [NSThread currentThread]];
    
    __weak typeof(self) weakSelf = self;
    NSOperation *logOperation = [NSBlockOperation blockOperationWithBlock:^{
        
        if(! weakSelf) { return; }
        __strong typeof(weakSelf) strongSelf = weakSelf;
        
        [strongSelf.logArray addObject:@{@"ts":ts, @"log":logStr}];
        //NSLog(@"%@", logStr);
    }];
    
    [_logQueue addOperation:logOperation];
}

-(void) sort2PrintLog {

    NSArray *logSorted = [_logArray sortedArrayUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
        NSDate *d1 = [((NSDictionary *)obj1) objectForKey:@"ts"];
        NSDate *d2 = [((NSDictionary *)obj2) objectForKey:@"ts"];
        
        return [d1 compare:d2];
    }];
    
    for(NSDictionary *logDic in logSorted) {
        NSString *log = [logDic objectForKey:@"log"];
        //NSLog(@"%@", log);
        
        printf("\nshareLogTS, sort2PrintLog, %s", [log cStringUsingEncoding:NSUTF8StringEncoding]);
    }
}

#pragma mark - 调测辅助 处理链图
#ifdef DEBUG

-(NSString *)makeChainTextShow {
    return @"";
}

-(CGSize) computeChainImageSize:(CGSize)sizeInNodeSpace {
    CGFloat nodeRadius = 50.f;  // 节点绘制半径
    CGFloat imageMargin = 50.f; // 绘图边距
    CGFloat hSpace = 100.f; // 节点间水平间距
    CGFloat vSpace = 60.f; // 节点间垂直间距
    
    // (rr)-h-(rr)
    CGFloat width = (sizeInNodeSpace.width)*(nodeRadius + hSpace + nodeRadius) + 2*(imageMargin + nodeRadius);
    CGFloat height = (sizeInNodeSpace.height)*(nodeRadius + vSpace + nodeRadius) + 2*(imageMargin + nodeRadius);
    
    _chainImageSize = CGSizeMake(width, height);
    
    return _chainImageSize;
}

-(CGPoint) getCordinateFromNode:(TBProcessNodeMC *)fnode {
    CGFloat nodeRadius = 50.f;  // 节点绘制半径
    CGFloat imageMargin = 50.f; // 绘图边距
    CGFloat hSpace = 100.f; // 节点间水平间距
    CGFloat vSpace = 60.f; // 节点间垂直间距
    
    CGFloat baseX = imageMargin + nodeRadius;
    CGFloat baseY = imageMargin + nodeRadius;
    
    CGPoint nodePoint = [fnode getNodeCordinate4Chain];
    CGFloat cx = baseX + (nodePoint.x * (nodeRadius + hSpace + nodeRadius));
    CGFloat cy = baseY + (nodePoint.y * (nodeRadius + vSpace + nodeRadius));
    
    // 左右、上下颠倒一下，因为结束节点 nodePoint 是 0，0
    return CGPointMake(_chainImageSize.width - cx, _chainImageSize.height - cy);
}

-(float) computeAngleFrom:(CGPoint)fromPoint to:(CGPoint)toPoint {
    if(toPoint.x == fromPoint.x) {
        if(toPoint.y > fromPoint.y) {
            return M_PI_2;
        } else {
            return -(M_PI_2);
        }
    } else {
        float dx = toPoint.x - fromPoint.x;
        float dy = toPoint.y - fromPoint.y;
        if(dx > 0) {
            return atanf(dy/dx);
        } else {
            return M_PI - (atanf(dy/(-dx)));
        }
    }
}

-(void) drawChainLine:(CGContextRef)context From:(TBProcessNodeMC *)fnode to:(TBProcessNodeMC *)tnode isStrong:(BOOL)isStrong {
    
    //线条宽
    CGContextSetLineWidth(context, 2.0);
    
    //线条颜色
    if(isStrong) {
        CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0); // 强关系设置为红色线条
    } else {
        CGContextSetRGBStrokeColor(context, 0.0, 1.0, 0.0, 1.0); // 弱关系设置为绿色线条
    }
    
    //坐标点数组
    //CGPoint aPoints[2];
    CGPoint fromPoint  = [self getCordinateFromNode:fnode];
    CGPoint toPoint = [self getCordinateFromNode:tnode];
    
    CGContextBeginPath(context);
    //添加线 points[]坐标数组，和count大小
    //CGContextAddLines(context, aPoints, 2);
    CGContextMoveToPoint(context, fromPoint.x, fromPoint.y);
    CGContextAddLineToPoint(context, toPoint.x, toPoint.y);
    
    CGPoint middlePoint = CGPointMake((fromPoint.x+toPoint.x)/2.f, (fromPoint.y+toPoint.y)/2.f);
    float arrowLineLen = 20;
    float lineAngle = [self computeAngleFrom:fromPoint to:toPoint];
    float lineAngle4arrowLineUp = lineAngle - M_PI_2 - M_PI_4;
    CGPoint arrowLineUpPoint = CGPointMake(middlePoint.x + arrowLineLen*cosf(lineAngle4arrowLineUp), middlePoint.y + arrowLineLen*sinf(lineAngle4arrowLineUp));
    CGContextMoveToPoint(context, middlePoint.x, middlePoint.y);
    CGContextAddLineToPoint(context, arrowLineUpPoint.x, arrowLineUpPoint.y);
    
    float lineAngle4arrowLineDown = lineAngle + M_PI_2 + M_PI_4;
    CGPoint arrowLineDownPoint = CGPointMake(middlePoint.x + arrowLineLen*cosf(lineAngle4arrowLineDown), middlePoint.y + arrowLineLen*sinf(lineAngle4arrowLineDown));
    CGContextMoveToPoint(context, middlePoint.x, middlePoint.y);
    CGContextAddLineToPoint(context, arrowLineDownPoint.x, arrowLineDownPoint.y);
    
    //CGContextClosePath(context);
    //根据坐标绘制路径
    CGContextDrawPath(context, kCGPathStroke);
}

-(void) drawNodeCircle:(CGContextRef)context node:(TBProcessNodeMC *)tnode {
    
    CGFloat nodeRadius = 50.f;  // 节点绘制半径
    
    //线条宽
    CGContextSetLineWidth(context, 4.0);
    
    CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
    
    switch (tnode.processStatus) {
        case TBProcessChainMCStatusNotWork:
            CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
            break;
        case TBProcessChainMCStatusWorking:
            CGContextSetFillColorWithColor(context, [UIColor yellowColor].CGColor);
            break;
        case TBProcessChainMCStatusGoSucc:
            CGContextSetFillColorWithColor(context, [UIColor greenColor].CGColor);
            break;
        case TBProcessChainMCStatusGoDie:
             CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
            break;
        default:
            break;
    }
    
    CGPoint cPoint = [self getCordinateFromNode:tnode];
    
    CGContextBeginPath(context);
    CGContextAddArc(context, cPoint.x,  cPoint.y, nodeRadius, 0, 2 * M_PI, 0);
    CGContextClosePath(context);
    
    CGContextDrawPath(context, kCGPathFillStroke);
    //CGContextFillPath(context);
    
    CGContextSetLineWidth(context, 1.0);//线条宽度
    CGContextSetRGBFillColor (context, 0.3, 0.3, 0.3, 1.0);//颜色
    UIFont *font = [UIFont boldSystemFontOfSize:18.0];
    [[tnode name4log] drawInRect:CGRectMake(cPoint.x-nodeRadius+5, cPoint.y-10, nodeRadius*2, 20) withAttributes:@{NSFontAttributeName:font}];
    
    if([self.keyProcessNodes containsObject:tnode]) {
        [@"key" drawInRect:CGRectMake(cPoint.x-nodeRadius+15, cPoint.y+10, nodeRadius*2, 20) withAttributes:@{NSFontAttributeName:font}];
    }

    if(tnode.endWorkTs && tnode.beginWorkTs) {
        float costInMS = (tnode.endWorkTs.timeIntervalSince1970 - tnode.beginWorkTs.timeIntervalSince1970)*1000.f;
        NSString *costInMSStr = [NSString stringWithFormat:@"%.0fms",costInMS];
        [costInMSStr drawInRect:CGRectMake(cPoint.x-nodeRadius+15, cPoint.y-30, nodeRadius*2, 20) withAttributes:@{NSFontAttributeName:font}];
    }
}

//保存图片
-(void)saveImage:(UIImage *)image {

    if(!image) {
        return;
    }
    
    if(PHAuthorizationStatusAuthorized != [PHPhotoLibrary authorizationStatus]) {
        return;
    }
    
    __block  NSString *assetLocalIdentifier;
    
    //__weak typeof(self) weakSelf = self;

    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
        //1.保存图片到相机胶卷中----创建图片的请求
        assetLocalIdentifier = [PHAssetCreationRequest creationRequestForAssetFromImage:image].placeholderForCreatedAsset.localIdentifier;
    } completionHandler:^(BOOL success, NSError * _Nullable error) {
        
        //if(! weakSelf) { return; }
        //__strong typeof(weakSelf) strongSelf = weakSelf;
        
    }];
}


//
-(UIImage *)makeChainImage {
    UIImage *chainImage = nil;
    if([_processNodeArray count] == 0) {
        return chainImage;
    }
    
    // 根据processNodeArray 中的坐标，计算坐标范围
    TBProcessNodeMC *firstNode = _processNodeArray.firstObject;
    CGPoint nodePoint = [firstNode getNodeCordinate4Chain];
    CGFloat minX = nodePoint.x;
    CGFloat maxX = nodePoint.x;
    CGFloat minY = nodePoint.y;
    CGFloat maxY = nodePoint.y;
    for(TBProcessNodeMC *pNode in _processNodeArray) {
        CGPoint nodePoint = [pNode getNodeCordinate4Chain];
        if (nodePoint.x < 0 || nodePoint.y < 0) {
            continue;
        }
        if(nodePoint.x < minX) {
            minX = nodePoint.x;
        }
        if(nodePoint.x > maxX) {
            maxX = nodePoint.x;
        }
        if(nodePoint.y < minY) {
            minY = nodePoint.y;
        }
        if(nodePoint.y > maxY) {
            maxY = nodePoint.y;
        }
    }
    
    [self computeChainImageSize:CGSizeMake(maxX - minX, maxY- minY)];
    
    // 绘图开始
    UIGraphicsBeginImageContext(_chainImageSize);
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetFillColorWithColor(context, [[UIColor colorWithRed:0.95f green:0.95f blue:0.95f alpha:1.0f] CGColor]);
    CGContextFillRect(context, CGRectMake(0, 0, _chainImageSize.width, _chainImageSize.height));
    
    // 绘制连接线
    for(TBProcessNodeMC *node in _processNodeArray) {
        NSArray *preList = [node getPreNodeList];
        if([preList count] == 0) {
            continue;
        }
        
        for (int loop=0; loop < [preList count]; loop += 2) {
            TBProcessNodeMC *preNode = (TBProcessNodeMC*)(preList[loop]);
            BOOL isStrong = [(preList[loop+1]) boolValue];
            
            [self drawChainLine:context From:preNode to:node isStrong:isStrong];
        }
    }
    
    // 绘制连节点
    for(TBProcessNodeMC *node in _processNodeArray) {
        [self drawNodeCircle:context node:node];
    }
    
    chainImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return chainImage;
}
#endif
 
#pragma mark - 处理链 启动 推动 停止

-(NSString *) checkProcessChainBeforeStart:(TBProcessNodeMC *)startNode {
    
    if(!startNode) {
        return @"startNode is empty";
    }
    
    if (! [_processNodeArray containsObject:startNode]) {
        return @"startNode is not in process chain";
    }
    
    if (! _finishProcessNode){
        return @"finishNode is not set";
    }
    
    NSMutableSet *allNodesVisited = [NSMutableSet set];
    NSMutableSet *allNodesThatNoPre = [NSMutableSet set];
    NSArray<TBProcessNodeMC *> *loopNodes = [TBProcessNodeMC applyDFS2DetectLoopFromFinishNode:_finishProcessNode
                                                                          chainNodesFromFinish:[NSMutableArray array]
                                                                               allNodesVisited:allNodesVisited
                                                                             allNodesThatNoPre:allNodesThatNoPre];
    
    if([loopNodes count]>0) {
        [self logEvent:@"checkProcessChainBeforeStart, 从处理链中发现环"];
        for(TBProcessNodeMC *node in loopNodes) {
            NSLog(@"  loop in chain: %@", [node name4log] );
        }
        return @"从处理链中发现环";
    }
    
    if([allNodesThatNoPre count] != 1) {
        for(TBProcessNodeMC *node in allNodesThatNoPre) {
            [self logEvent:[NSString stringWithFormat:@"   allNodesThatNoPre: %@", [node name4log]]];
        }
        return @"从处理链结束节点 遍历得到的 起始节点 不唯一";
    }
    
    TBProcessNodeMC *nodeNoPre = allNodesThatNoPre.allObjects.firstObject;
    if(startNode != nodeNoPre) {
        [self logEvent:@"checkProcessChainBeforeStart, 从处理链结束节点 遍历得到的 起始节点 和 当前起始节点 不相等"];
        [self logEvent:[NSString stringWithFormat:@"   startNode %@ != allNodesThatNoPre.firstObject %@", [startNode name4log], [nodeNoPre name4log]]];
        return @"从处理链结束节点 遍历得到的 起始节点 和 当前起始节点 不相等";
    }
    
    if([allNodesVisited count] != [_processNodeArray count]) {
        [self logEvent:@"checkProcessChainBeforeStart, 从处理链结束节点遍历得到的节点数组 和 处理链节点数组 数量不等"];
        return @"从处理链结束节点遍历得到的节点数组 和 处理链节点数组 数量不等";
    }
    
    for (TBProcessNodeMC *pNode in _processNodeArray) {
        if(! [allNodesVisited containsObject:pNode]) {
            [self logEvent:@"checkProcessChainBeforeStart, 从处理链结束节点遍历得到的节点数组 和 处理链节点数组 数量相同 但不全等"];
            [self logEvent:[NSString stringWithFormat:@"   %@ in _processNodeArray, but not in allNodesVisited", [pNode name4log]]];
            return @"从处理链结束节点遍历得到的节点数组 和 处理链节点数组 数量相同 但不全等";
        }
    }
    
    return nil;
}

// 从 processNodeArray 第一个节点开始启动 处理链
-(void) start {
    
    TBProcessNodeMC *firstNode = [self.processNodeArray firstObject];
    
    [self startWithNode:firstNode];
}

// 从 processNodeArray 某个节点开始启动 处理链
-(void) startWithNode:(TBProcessNodeMC *)startNode {
    if(_processStatus != TBProcessChainMCStatusNotWork) {
        // 启动条件 处理链处于 NotWork 状态
        return;
    }
    
    NSString *preCheckError = [self checkProcessChainBeforeStart:startNode];
    
    if([preCheckError length] > 0) {
        
        __weak typeof(self) weakSelf = self;

        excuteInQueue(_blockRunInMainThread, ^{
            if(! weakSelf) { return; }
            __strong typeof(weakSelf) strongSelf = weakSelf;
            
            strongSelf.failBlock(@{@"why" : preCheckError});
        });
        
        if(_applyLog) {
            [self sort2PrintLog];
        }
        
        return;
    }
    
    _processStatus = TBProcessChainMCStatusWorking;
    self.beginWorkTs = [[NSDate alloc]init];
    
    if(_timeOut4Process > 0.f) {
        // 超时逻辑
        __weak typeof(self) wSelf = self;
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_timeOut4Process * NSEC_PER_SEC)),
                       dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
                       ^{
                            if(! wSelf) {
                                NSLog(@"---> timeout, TBProcessChainMC, wSelf==nil, no operation");
                                return;
                            }
                            __strong typeof(wSelf) strongSelf = wSelf;
            
                            [strongSelf logEvent:@"timeout, TBProcessChainMC before applyTimeoutStopInQueue"];
            
                            [strongSelf applyTimeoutStopInQueue];
        });
    }
    
    [startNode forceBegin];
}

-(void) applyTimeoutStopInQueue {
    __weak typeof(self) weakSelf = self;
    NSOperation *dieOperation = [NSBlockOperation blockOperationWithBlock:^{
        if(! weakSelf) { return; }
        __strong typeof(weakSelf) strongSelf = weakSelf;
        [strongSelf stop:NO info:@{@"why":@"timeOut"}];
    }];
    
    [_handleQueue addOperation:dieOperation];
}

-(void) stop:(BOOL)succ {
    [self stop:succ info:nil];
}

// 显示强制停止处理
-(void) stop:(BOOL)succ info:(NSDictionary * _Nullable)info {
    
    [self logEvent:[NSString stringWithFormat:@"stop(%@), TBProcessChainMC begin", (succ?@"YES":@"NO")]];
    
    if(_processStatus != TBProcessChainMCStatusWorking) {
        
        [self logEvent:[NSString stringWithFormat:@"stop(%@), TBProcessChainMC, _processStatus != TBProcessChainMCStatusWorking, no operation", (succ?@"YES":@"NO")]];
        
        return;
    }
    _processStatus = succ ? TBProcessChainMCStatusGoSucc : TBProcessChainMCStatusGoDie;
    
    // log队列还没有执行的 都停止
    [_logQueue cancelAllOperations];
    // 执行队列还没有执行的 都停止
    [_handleQueue cancelAllOperations];
    
    // 做结束回调
    self.endWorkTs = [[NSDate alloc]init];
    float processTimeInMS = self.endWorkTs.timeIntervalSince1970 - self.beginWorkTs.timeIntervalSince1970;
    processTimeInMS *= 1000.f;
    
    NSMutableDictionary *callBackInfo = [NSMutableDictionary dictionaryWithDictionary:info];
    callBackInfo[@"processTimeInMS"] = @(processTimeInMS);
    
    __weak typeof(self) weakSelf = self;
    if(succ) {
        if(_succBlock) {
            excuteInQueue(_blockRunInMainThread, ^{
                if(! weakSelf) { return; }
                __strong typeof(weakSelf) strongSelf = weakSelf;
                
                strongSelf.succBlock(callBackInfo);
            });
        }
    } else {
        if(_failBlock) {
            excuteInQueue(_blockRunInMainThread, ^{
                if(! weakSelf) { return; }
                __strong typeof(weakSelf) strongSelf = weakSelf;
                
                strongSelf.failBlock(callBackInfo);
            });
        }
    }

#ifdef DEBUG
    if(self.makeChainImageWhenEnd) {
        
        // 将处理链拓扑结构 和 运行信息绘制到图片上
        [self logEvent:@"before makeChainImage"];
        UIImage *chainImage = [self makeChainImage];
        
        if(chainImage) {
            
            // 将处理链拓扑结构 和 运行信息绘制到图片上，存入系统相册，仅在调试模式work
            [self logEvent:@"after makeChainImage, before saveImage"];
            [self saveImage:chainImage];
            
            [self logEvent:@"after saveImage"];
            
        } else {
            [self logEvent:@"after makeChainImage, no chainImage"];
        }
    }
#endif
    
    // 在处理链结束前被调用各个节点的 清理逻辑，单个节点清理的默认动作 解除节点之间的相互应用
    @synchronized (_processNodeArray) {
        for (TBProcessNodeMC *pNode in _processNodeArray) {
            [pNode cleanBeforeStop];
        }
        
        [self.processNodeArray removeAllObjects];
    }
    
    @synchronized (_keyProcessNodes) {
        [self.keyProcessNodes removeAllObjects];
    }
    
    self.finishProcessNode = nil;
    
    if(_applyLog) {
        [self sort2PrintLog];
    }
}

/*
-(void) loop2CheckNodes2work:(TBProcessNodeMC *)processNode {
    @synchronized (self) {
        if(_processStatus != TBProcessChainMCStatusWorking) {
            return;
        }
        
        @synchronized (_processNodeArray) {
            for (TBProcessNodeMC *pNode in _processNodeArray) {
                [pNode checkPreNodes2work:processNode];
            }
        }
    }
}
//*/

-(void) check2DriveProcessChain:(TBProcessNodeMC *)processNode {
    if(_processStatus != TBProcessChainMCStatusWorking) {
        return;
    }
    
    @synchronized (_processNodeArray) {
        for (TBProcessNodeMC *pNode in _processNodeArray) {
            [pNode checkPreNodes2work:processNode];
        }
    }
    
    /*
    __weak typeof(self) weakSelf = self;
    excuteInGlobleQueue(^{
        if(! weakSelf) {
            return;
        }
        __strong typeof(weakSelf) strongSelf = weakSelf;
        
        [strongSelf loop2CheckNodes2work:processNode];
    });
    //*/
}

-(void) handleNodeGoDie:(TBProcessNodeMC *)processNode dieInfo:(NSDictionary * _Nullable)dieInfo {
    __weak typeof(self) weakSelf = self;
    NSOperation *dieOperation = [NSBlockOperation blockOperationWithBlock:^{
        if(! weakSelf) {
            return;
        }
        __strong typeof(weakSelf) strongSelf = weakSelf;
        [strongSelf handleNodeGoDieOperation:processNode dieInfo:dieInfo];
    }];
    
    [_handleQueue addOperation:dieOperation];
}

-(void) handleNodeGoDieOperation:(TBProcessNodeMC *)processNode dieInfo:(NSDictionary * _Nullable)dieInfo {
    
    [self logEvent:[NSString stringWithFormat:@"nodeGoDie, %@", [processNode name4log]]];
    
    [self logEvent:dieInfo];
    
    if(_processStatus != TBProcessChainMCStatusWorking) {
        [self logEvent:[NSString stringWithFormat:@"nodeGoDie, %@, _processStatus != TBProcessChainMCStatusWorking", [processNode name4log]]];
        return;
    }
    
    if (!processNode){
        return;
    }

    // 信息打印
    //String nodeClassName = preNode.getClass().getSimpleName();
    //this.infoShowObj.showError("goDie : "+ nodeClassName +", lastWords : " + lastWords);
    //this.infoShowObj.logEvent("goDie : "+ nodeClassName +", lastWords : " + lastWords);
    
    // 如果关键节点狗带，处理链停止工作
    if([_keyProcessNodes containsObject:processNode]) {
        [self stop:NO info:dieInfo];
        
        return;
    }

    // 如果是 结束节点
    if(_finishProcessNode == processNode) {
        [self stop:NO info:dieInfo];
        return;
    }
    
    
    [self check2DriveProcessChain:processNode];
    
}

-(void) handleNodeFinish:(TBProcessNodeMC *)processNode succInfo:(NSDictionary * _Nullable)succInfo {
    __weak typeof(self) weakSelf = self;
    NSOperation *dieOperation = [NSBlockOperation blockOperationWithBlock:^{
        if(! weakSelf) {
            return;
        }
        __strong typeof(weakSelf) strongSelf = weakSelf;
        [strongSelf handleNodeFinishOperation:processNode succInfo:succInfo];
    }];
    
    [_handleQueue addOperation:dieOperation];
}

-(void) handleNodeFinishOperation:(TBProcessNodeMC *)processNode succInfo:(NSDictionary * _Nullable)succInfo {
    
    [self logEvent:[NSString stringWithFormat:@"nodeFinish, %@", [processNode name4log]]];
    [self logEvent:succInfo];
    if(_processStatus != TBProcessChainMCStatusWorking) {
        [self logEvent:[NSString stringWithFormat:@"nodeFinish, %@, _processStatus != TBProcessChainMCStatusWorking", [processNode name4log]]];
        return;
    }
    
    if (!processNode){
        return;
    }
    
    // 信息打印
    //String nodeClassName = preNode.getClass().getSimpleName();
    //this.infoShowObj.showError("goDie : "+ nodeClassName +", lastWords : " + lastWords);
    //this.infoShowObj.logEvent("goDie : "+ nodeClassName +", lastWords : " + lastWords);
    
    // 如果是 结束节点
    if(_finishProcessNode == processNode) {

        [self stop:YES info:succInfo];
        return;
    }
    
    [self check2DriveProcessChain:processNode];
}

#pragma mark - 处理链构建

// 设置关键节点，这些节点出错，正处理链中断处理
-(void) setKeyProcessNode:(NSArray<TBProcessNodeMC *> *)keyNodes {
    @synchronized(_keyProcessNodes) {
        for(TBProcessNodeMC *pNode in keyNodes) {
            // 添加到所有节点列表
            [self addNodeIntoChain:pNode];
            
            // 添加到关键节点列表
            if(! [_keyProcessNodes containsObject:pNode]) {
                [_keyProcessNodes addObject:pNode];
            }
        }
    }
}

-(void) addNodeIntoChain:(TBProcessNodeMC *)pNode {
    if(! pNode) {
        return;
    }
    
    pNode.processChain = self;

    @synchronized(_processNodeArray) {
        if(! [_processNodeArray containsObject:pNode]) {
            [_processNodeArray addObject:pNode];
        }
    }
}

// 向处理链添加两个节点，并且设置前后关联关系 preNode --(isStrong)--> subNode
-(void) addNodeIntoChain:(TBProcessNodeMC *)preNode subNode:(TBProcessNodeMC *)subNode isStrongRelation:(BOOL)isStrong {
    if(preNode == nil || subNode == nil) {
        return;
    }

    [self addNodeIntoChain:preNode];
    [self addNodeIntoChain:subNode];
    
    
    [subNode addPreNode:preNode preStrong:isStrong];
}

// 向处理链添加preNode节点 和 subNodeList中所有节点，并且设置前后关联关系
//  preNode --(isStrong)--> subNode[0]
//  preNode --(isStrong)--> subNode[1]
//  ...
//  preNode --(isStrong)--> subNode[n-1]
-(void) addNodeIntoChain:(TBProcessNodeMC *)preNode subNodeList:(NSArray<TBProcessNodeMC *> *)subNodeList isStrongRelation:(BOOL)isStrong {
    if(preNode == nil || [subNodeList count] == 0) {
        return;
    }
    [self addNodeIntoChain:preNode];
    
    for(TBProcessNodeMC *subNode in subNodeList) {
        [self addNodeIntoChain:subNode];
        [subNode addPreNode:preNode preStrong:isStrong];
    }
}

// 向处理链添加preNodeList中所有节点 和 subNode，并且设置前后关联关系
//  preNode[0] --(isStrong)--> subNode
//  preNode[1] --(isStrong)--> subNode
//  ...
//  preNode[n-1] --(isStrong)--> subNode
-(void) addNodeListIntoChain:(NSArray<TBProcessNodeMC *> *)preNodeList subNode:(TBProcessNodeMC *)subNode isStrongRelation:(BOOL)isStrong {
    if(subNode == nil || [preNodeList count] == 0) {
        return;
    }
    
    [self addNodeIntoChain:subNode];
    
    for(TBProcessNodeMC *preNode in preNodeList) {
        [self addNodeIntoChain:preNode];
        [subNode addPreNode:preNode preStrong:isStrong];
    }
}

// 向处理链添加n个节点，并且设置前后关联关系 pNodes[0] --(isStrong)--> pNodes[1] --(isStrong)--> pNodes[2] ...  --(isStrong)--> pNodes[n-1]
-(void) addNodeSequeceIntoChain:(NSArray<TBProcessNodeMC *> *)pNodes isStrongRelation:(BOOL)isStrong {
    if([pNodes count] == 0) {
        return;
    }
    
    if([pNodes count] == 1) {
        [self addNodeIntoChain:pNodes.firstObject];
        return;
    }
    
    for(int loop=0; loop<[pNodes count] -1 ; ++ loop) {
        [self addNodeIntoChain:pNodes[loop] subNode:pNodes[loop+1] isStrongRelation:isStrong];
    }
}

// 设置结束节点，结束节点完成后，正处理链操作完成
-(void) setFinishNode:(TBProcessNodeMC *)finishNode {
    self.finishProcessNode = finishNode;
}

@end
